home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 April / EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso / EARCD / text / hyper / hsc_source.lha / hsc / source / hsclib / eval.c < prev    next >
C/C++ Source or Header  |  1996-12-04  |  38KB  |  1,444 lines

  1. /*
  2.  * hsclib/eval.c
  3.  *
  4.  * attribute value evaluation functions
  5.  *
  6.  * Copyright (C) 1995,96  Thomas Aglassinger
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  * updated:  4-Dec-1995
  23.  * created: 11-Oct-1995
  24.  */
  25.  
  26. #define NOEXTERN_HSCLIB_EVAL_H
  27.  
  28. #include <ctype.h>
  29. #include <time.h>
  30.  
  31. #include "hsclib/inc_base.h"
  32.  
  33. #include "hsclib/eval.h"
  34. #include "hsclib/input.h"
  35. #include "hsclib/skip.h"
  36. #include "hsclib/uri.h"
  37.  
  38. /* maximul length of an operator identifer */
  39. #define MAX_OP_LEN 8
  40.  
  41. /* unknown operator */
  42. #define OP_NONE 0
  43.  
  44. /* step-size for temp. string */
  45. #define TMP_STEPSIZE 128
  46.  
  47. /*
  48.  * equation operators
  49.  */
  50. #define OP_EQ_STR  "="
  51. #define OP_NEQ_STR "<>"
  52. #define OP_GT_STR  ">"
  53. #define OP_LT_STR  "<"
  54. #define OP_GTE_STR ">="
  55. #define OP_LTE_STR "<="
  56. #define OP_CEQ_STR "=="         /* TODO: case sensitive string comparison */
  57. #define OP_INSIDE_STR "IN"      /* TODO: check for substring */
  58. #define OP_CL_BRAKET_STR ")"    /* closing braket */
  59.  
  60. #define OP_EQ   1
  61. #define OP_NEQ  2
  62. #define OP_GT   3
  63. #define OP_LT   4
  64. #define OP_GTE  5
  65. #define OP_LTE  6
  66. #define OP_CEQ  7
  67. #define OP_INSIDE 8
  68. #define OP_CL_BRAKET  10
  69.  
  70. /*
  71.  * boolean operators
  72.  */
  73. #define OP_AND_STR "AND"
  74. #define OP_NOT_STR "NOT"
  75. #define OP_OR_STR  "OR"
  76. #define OP_XOR_STR "XOR"
  77.  
  78. #define OP_AND 11
  79. #define OP_NOT 12
  80. #define OP_OR  13
  81. #define OP_XOR 14
  82.  
  83. /*
  84.  * string operators
  85.  */
  86. #define OP_CAT_STR "+"
  87. #define OP_CAT      15
  88.  
  89. typedef BYTE op_t;
  90.  
  91. /*
  92.  * forward references
  93.  */
  94. STRPTR eval_expression(HSCPRC * hp, HSCATTR * dest, STRPTR endstr);
  95.  
  96. /*
  97.  * 
  98.  * global funcs
  99.  *
  100.  */
  101.  
  102. /*
  103.  * err_op: unknown binary operator
  104.  */
  105. static VOID err_op(HSCPRC * hp, STRPTR opstr)
  106. {
  107.     hsc_message(hp, MSG_UNKN_BINOP, "unknown binary operator %q", opstr);
  108. }
  109.  
  110. /*
  111.  * eval_boolstr
  112.  */
  113. static BOOL eval_boolstr(STRPTR s)
  114. {
  115.     if (s[0])
  116.         return (TRUE);
  117.     else
  118.         return (FALSE);
  119. }
  120.  
  121. /* check for empty brakets (after GetTime/GetGmTime) */
  122. static VOID check_brakets(HSCPRC * hp)
  123. {
  124.     if (parse_wd(hp, "("))
  125.         parse_wd(hp, ")");
  126. }
  127.  
  128. /*
  129.  * gettimestr
  130.  */
  131. static EXPSTR *gettimestr(HSCPRC * hp, struct tm *time)
  132. {
  133. #define TIMEBUF_INC 20
  134.     STRPTR timefmt = get_vartext_byname(hp->defattr, TIMEFORMAT_ATTR);
  135.     EXPSTR *timebuf = init_estr(TIMEBUF_INC);
  136.     BOOL strftrc = 0;           /* result of strftime() */
  137.     size_t i;                   /* loop var */
  138.  
  139.     /* set default time format */
  140.     if (!timefmt)
  141.         timefmt = "%d-%b-%Y, %H:%M";
  142.  
  143.     while (!(hp->fatal) && !strftrc)
  144.     {
  145.         /* expand timebuffer */
  146.         for (i = 0; i < TIMEBUF_INC; i++)
  147.             app_estrch(timebuf, '.');
  148.  
  149.         D(fprintf(stderr, DHL "    timebuf: inc+%d\n", TIMEBUF_INC));
  150.  
  151.         /* output time */
  152.         strftrc = strftime(estr2str(timebuf), estrlen(timebuf),
  153.                            timefmt, time);
  154.     }
  155.  
  156.     if (!strftrc)
  157.     {
  158.         del_estr(timebuf);
  159.         timebuf = NULL;
  160.     }
  161.  
  162.     return (timebuf);
  163. }
  164.  
  165. /*
  166.  * getfilesize
  167.  *
  168.  * get size of a specific file
  169.  *
  170.  * templates for HSC.FORMAT.FILESIZE:
  171.  * %b   size in byte
  172.  * %k   size in Kbyte
  173.  * %m   size in MByte
  174.  * %g   size in Gbyte
  175.  * %a   size, unit computed automatically
  176.  * %u   unit for %A (none, "K", "M" or "G")
  177.  */
  178. static STRPTR getfilesize(HSCPRC * hp, EXPSTR * dest, STRPTR uri)
  179. {
  180.     STRPTR filesizestr = NULL;
  181.     FILE *file = NULL;
  182.     LONG filesize = 0;          /* filesize in byte */
  183.     LONG filesize_k = 0;        /* filesize in Kbyte */
  184.     LONG filesize_m = 0;        /* filesize in Mbyte */
  185.     LONG filesize_g = 0;        /* filesize in Gbyte */
  186.     LONG filesize_auto = 0;     /* filesize in auto-units (%A) */
  187.     EXPSTR *efilename = init_estr(32);
  188.     STRPTR filename = NULL;
  189.     STRPTR sizeunit = "";
  190.     STRPTR s = get_vartext_byname(hp->defattr,
  191.                                   FILESIZEFORMAT_ATTR);
  192.  
  193.     conv_hscuri2file(hp, efilename, uri);
  194.     filename = estr2str(efilename);
  195.  
  196.     D(fprintf(stderr, DHL "  GETFILESIZE(`%s')\n", filename));
  197.     errno = 0;
  198.     file = fopen(filename, "rb");
  199.     if (file)
  200.     {
  201.         /* retrieve size */
  202.         fseek(file, 0L, SEEK_END);
  203.         filesize = ftell(file);
  204.         fclose(file);
  205.  
  206.         /* compute size in units, */
  207.         filesize_k = (filesize + 512) >> 10;
  208.         filesize_m = (filesize_k + 512) >> 10;
  209.         filesize_g = (filesize_m + 512) >> 10;
  210.  
  211.         /* compute auto-size */
  212.         if (filesize_g > 10)
  213.         {
  214.             filesize_auto = filesize_g;
  215.             sizeunit = "G";
  216.         }
  217.         else if (filesize_m > 10)
  218.         {
  219.             filesize_auto = filesize_m;
  220.             sizeunit = "M";
  221.         }
  222.         else if (filesize_k > 10)
  223.         {
  224.             filesize_auto = filesize_k;
  225.             sizeunit = "K";
  226.         }
  227.         else
  228.         {
  229.             filesize_auto = filesize;
  230.             sizeunit = "";
  231.         }
  232.     }
  233.     else
  234.     {
  235.         /* file not found */
  236.         filesize = 0;
  237.         filesize_k = 0;
  238.         filesize_m = 0;
  239.         filesize_g = 0;
  240.         filesize_auto = 0;
  241.         sizeunit = "";
  242.         hsc_msg_nouri(hp, filename, uri, "get filesize");
  243.     }
  244.  
  245.     /* parse template */
  246.     clr_estr(dest);
  247.     if (s)
  248.     {
  249.         while (s[0])
  250.         {
  251.             if (s[0] == '%')
  252.             {
  253.                 if (s[1])
  254.                     s++;
  255.                 switch (s[0])
  256.                 {
  257.                 case 'b':
  258.                     app_estr(dest, long2str(filesize));
  259.                     break;
  260.  
  261.                 case 'k':
  262.                     app_estr(dest, long2str(filesize_k));
  263.                     break;
  264.  
  265.                 case 'm':
  266.                     app_estr(dest, long2str(filesize_m));
  267.                     break;
  268.  
  269.                 case 'g':
  270.                     app_estr(dest, long2str(filesize_g));
  271.                     break;
  272.  
  273.                 case 'a':
  274.                     app_estr(dest, long2str(filesize_auto));
  275.                     break;
  276.  
  277.                 case 'u':
  278.                     app_estr(dest, sizeunit);
  279.                     break;
  280.  
  281.                 default:
  282.                     app_estrch(dest, '%');
  283.                     app_estrch(dest, s[0]);
  284.                     break;
  285.                 }
  286.             }
  287.             else
  288.                 app_estrch(dest, s[0]);
  289.             s++;
  290.         }
  291.     }
  292.     else
  293.     {
  294.         D(panic("no template for filesize-format"));
  295.     }
  296.  
  297.     /* set filesize-str */
  298.     filesizestr = estr2str(dest);
  299.     D(fprintf(stderr, DHL "  =`%s'\n", filesizestr));
  300.  
  301.     del_estr(efilename);
  302.  
  303.     return (filesizestr);
  304. }
  305.  
  306. /*
  307.  * check_attrname
  308.  *
  309.  * check string for legal attribute name
  310.  */
  311. BOOL check_attrname(HSCPRC * hp, STRPTR name)
  312. {
  313.     BOOL ok = FALSE;
  314.  
  315.     if (hsc_normch(name[0]))
  316.         ok = TRUE;
  317.     else
  318.         hsc_message(hp, MSG_ILLG_ATTRNAME,
  319.                     "illegal attribute identifier %q", name);
  320.  
  321.     return (ok);
  322. }
  323.  
  324. /*
  325.  * eval_attrname
  326.  *
  327.  * read next word and check it for a legal
  328.  * attribute identifier
  329.  */
  330. static STRPTR eval_attrname(HSCPRC * hp)
  331. {
  332.     STRPTR result = NULL;
  333.     STRPTR nw = infgetw(hp->inpf);
  334.  
  335.     if (nw)
  336.     {
  337.         if (check_attrname(hp, nw))
  338.             result = nw;
  339.     }
  340.     else
  341.         hsc_msg_eof(hp, "attribute identifier expected");
  342.  
  343.     return (result);
  344. }
  345.  
  346. /*
  347.  * quotestr
  348.  *
  349.  * return readable string for quote-kind
  350.  */
  351. #define DOUBLE_QUOTE '\"'
  352. #define SINGLE_QUOTE '\''
  353. STRPTR quotestr(int quote)
  354. {
  355.     STRPTR s = "UNKNOWN";
  356.  
  357.     if (quote == DOUBLE_QUOTE)
  358.         s = "[double]";
  359.     else if (quote == SINGLE_QUOTE)
  360.         s = "[single]";
  361.     else if (quote == VQ_NO_QUOTE)
  362.         s = "[none]";
  363.     else
  364.     {
  365.         STRARR tmp[60];
  366.         sprintf(tmp, "unknown quote-kind: $%02x #%03d", quote, quote);
  367.         panic(tmp);
  368.     }
  369.  
  370.     return (s);
  371. }
  372.  
  373. /*
  374.  * choose_quote
  375.  *
  376.  * choose quote to be used for attr, depending on
  377.  * hp->quotemode and quotes used inside the value
  378.  */
  379. static VOID choose_quote(HSCPRC * hp, HSCATTR * attr)
  380. {
  381.     int quote = attr->quote;
  382.     LONG qm = hp->quotemode;    /* lazy.. */
  383.     BOOL single_quote = FALSE;
  384.     BOOL double_quote = FALSE;
  385.     BOOL nasty_char = FALSE;
  386.  
  387.     STRPTR value = get_vartext(attr);
  388.  
  389.     D(fprintf(stderr, DHL "  choosing quote\n"));
  390.  
  391.     if (value[0])
  392.     {
  393.         /* scan attribute value for quotes */
  394.         while (value[0])
  395.         {
  396.             if (value[0] == SINGLE_QUOTE)
  397.             {
  398.                 D(fprintf(stderr, DHL "    single quote detected\n"));
  399.                 single_quote = TRUE;
  400.                 nasty_char = TRUE;
  401.             }
  402.             else if (value[0] == DOUBLE_QUOTE)
  403.             {
  404.                 D(fprintf(stderr, DHL "    double quote detected\n"));
  405.                 double_quote = TRUE;
  406.                 nasty_char = TRUE;
  407.             }
  408.             else if (!hsc_normch(value[0]) && !nasty_char)
  409.             {
  410.                 D(fprintf(stderr, DHL "    nasty-char #%d detected\n", value[0]));
  411.                 nasty_char = TRUE;
  412.             }
  413.  
  414.             value++;
  415.         }
  416.     }
  417.     else
  418.     {
  419.         /* empty value */
  420.         nasty_char = TRUE;
  421.         /* TODO: warninbg "empty value" */
  422.     }
  423.  
  424.     if (qm == QMODE_KEEP)
  425.     {
  426.         /* check, if quote is missing */
  427.         if ((attr->quote == VQ_NO_QUOTE)
  428.             && nasty_char)
  429.         {
  430.             hsc_message(hp, MSG_REQU_QUOTE,
  431.                         "value for %A requires quotes", attr);
  432.         }
  433.     }
  434.     else
  435.     {
  436.         /* choose quote */
  437.         if (single_quote && double_quote)
  438.         {
  439.             /* both kind of quotes appeared in value:
  440.              * replace double-quotes by """ */
  441.             EXPSTR *newval = init_estr(32);     /* new attribute value */
  442.  
  443.             /* scan old value for `\"', replace them by `"'
  444.              * and store new value in newval */
  445.             value = get_vartext(attr);
  446.             while (value[0])
  447.             {
  448.                 if (value[0] == DOUBLE_QUOTE)
  449.                 {
  450.                     D(fprintf(stderr, DHL "    replace by `"' in value\n"));
  451.                     /* TODO: message */
  452.                     app_estr(newval, """);
  453.                 }
  454.                 else
  455.                     app_estrch(newval, value[0]);
  456.                 value++;
  457.             }
  458.  
  459.             /* update attribute value */
  460.             set_vartext(attr, estr2str(newval));
  461.  
  462.             quote = DOUBLE_QUOTE;
  463.  
  464.             del_estr(newval);
  465.         }
  466.         else
  467.         {
  468.             if (single_quote)
  469.             {
  470.                 D(fprintf(stderr, DHL "    double quote forced\n"));
  471.                 quote = DOUBLE_QUOTE;
  472.             }
  473.             else if (double_quote)
  474.             {
  475.                 D(fprintf(stderr, DHL "    single quote forced\n"));
  476.                 quote = SINGLE_QUOTE;
  477.             }
  478.             else
  479.             {
  480.                 /* no quote in value: choose quote user prefers */
  481.                 if (qm == QMODE_SINGLE)
  482.                 {
  483.                     D(fprintf(stderr, DHL "    single quote preferd\n"));
  484.                     quote = SINGLE_QUOTE;
  485.                 }
  486.                 else if (qm == QMODE_DOUBLE)
  487.                 {
  488.                     D(fprintf(stderr, DHL "    double quote prefered\n"));
  489.                     quote = DOUBLE_QUOTE;
  490.                 }
  491.                 else if (qm == QMODE_NONE)
  492.                 {
  493.                     if (nasty_char)
  494.                     {
  495.                         D(fprintf(stderr, DHL "    quote needed (nasty char)\n"));
  496.                         quote = DOUBLE_QUOTE;
  497.                     }
  498.                     else
  499.                     {
  500.                         D(fprintf(stderr, DHL "    no quote needed\n"));
  501.                         quote = VQ_NO_QUOTE;
  502.                     }
  503.                 }
  504.                 else
  505.                 {
  506.                     panic("illegal quote-mode");
  507.                 }
  508.             }
  509.         }
  510.         /* check, if quote has changed */
  511.         if (attr->quote != quote)
  512.         {
  513.             hsc_message(hp, MSG_CHANGED_QUOTE,
  514.                         "changed quotes for %A from %s to %s",
  515.                         attr, quotestr(attr->quote), quotestr(quote));
  516.         }
  517.     }
  518.  
  519.     attr->quote = quote;
  520. }
  521.  
  522. /*
  523.  * try_eval_unary_op
  524.  *
  525.  * reads next word and tries to interpret it as an unary
  526.  * operator; if no fitting operator exists, return NULL,
  527.  * else immediatly process the operator and return its
  528.  * result
  529.  */
  530. static STRPTR try_eval_unary_op(HSCPRC * hp, HSCATTR * dest, BOOL * err)
  531. {
  532.     STRPTR eval_result = NULL;
  533.     INFILE *inpf = hp->inpf;
  534.     STRPTR nw = eval_attrname(hp);
  535.     HSCATTR *tmpdest = new_hscattr(PREFIX_TMPATTR "unary.operator");
  536.  
  537.     tmpdest->vartype = VT_STRING;
  538.  
  539.     *err = FALSE;
  540.     if (nw)
  541.     {
  542.         if (!upstrcmp(nw, "NOT"))
  543.         {
  544.             /* TODO: this part looks a bit stupid... */
  545.             STRPTR nw = infgetw(inpf);
  546.  
  547.             if (nw)
  548.             {
  549.                 BOOL err_rec = FALSE;   /* error var for recursive call */
  550.                 STRPTR endstr = NULL;
  551.  
  552.                 if (strcmp(nw, "("))
  553.                 {
  554.                     /* try to process another unary operator */
  555.                     inungetcw(inpf);
  556.                     eval_result = try_eval_unary_op(hp, dest, &err_rec);
  557.                 }
  558.                 else
  559.                     endstr = ")";
  560.  
  561.                 /* if not, process another expression */
  562.                 if (!eval_result && !err_rec)
  563.                     eval_result = eval_expression(hp, dest, endstr);
  564.             }
  565.             else
  566.                 hsc_msg_eof(hp, "after NOT");
  567.  
  568.             /* set result or return error */
  569.             if (eval_result)
  570.             {
  571.                 set_varbool(dest, !get_varbool(dest));
  572.                 eval_result = get_vartext(dest);
  573.             }
  574.             else
  575.                 *err = TRUE;
  576.         }
  577.         else if (!upstrcmp(nw, "DEFINED"))
  578.         {
  579.             nw = eval_attrname(hp);
  580.             if (nw)
  581.             {
  582.                 HSCATTR *attr = find_varname(hp->defattr, nw);
  583.  
  584.                 if (attr)
  585.                     set_varbool(dest, TRUE);
  586.                 else
  587.                     set_varbool(dest, FALSE);
  588.                 eval_result = get_vartext(dest);
  589.             }
  590.         }
  591.         else if (!upstrcmp(nw, "EXISTS"))
  592.         {
  593.             /* check existence of file */
  594.             eval_result = eval_expression(hp, tmpdest, NULL);
  595.             if (eval_result)
  596.             {
  597.                 FILE *file = NULL;
  598.                 EXPSTR *dest_fname = init_estr(64);
  599.  
  600.                 D(fprintf(stderr, DHL "  EXISTS(`%s')\n", eval_result));
  601.  
  602.                 conv_hscuri2file(hp, dest_fname, eval_result);
  603.                 file = fopen(eval_result, "r");
  604.                 if (file)
  605.                 {
  606.                     fclose(file);
  607.                     set_varbool(dest, TRUE);
  608.                 }
  609.                 else
  610.                     set_varbool(dest, FALSE);
  611.  
  612.                 del_estr(dest_fname);
  613.                 eval_result = get_vartext(dest);
  614.             }
  615.         }
  616.         else if (!upstrcmp(nw, "GETENV"))
  617.         {
  618.             /* get environment variable */
  619.             eval_result = eval_expression(hp, dest, NULL);
  620.             if (eval_result)
  621.             {
  622.                 STRPTR env_value = getenv(get_vartext(dest));
  623.  
  624.                 D(fprintf(stderr, DHL "  GETENV(`%s')\n", eval_result));
  625.                 if (!env_value)
  626.                 {
  627.                     hsc_message(hp, MSG_UNKN_ENVVAR,
  628.                                 "unknown environment variable %q",
  629.                                 get_vartext(dest));
  630.  
  631.                     env_value = "";
  632.                 }
  633.                 set_vartext(dest, env_value);
  634.                 eval_result = get_vartext(dest);
  635.                 D(fprintf(stderr, DHL "  =`%s'\n", eval_result));
  636.             }
  637.         }
  638.         else if (!upstrcmp(nw, "GETFILESIZE"))
  639.         {
  640.             /* retrieve size of a file */
  641.             EXPSTR *filesizestr = init_estr(0);
  642.             HSCATTR *filedestattr = new_hscattr(PREFIX_TMPATTR "get.filesize");
  643.             STRPTR filename = NULL;
  644.  
  645.             eval_result = NULL;
  646.             filedestattr->vartype = VT_STRING;
  647.             filename = eval_expression(hp, filedestattr, NULL);
  648.             if (filename)
  649.             {
  650.                 eval_result = getfilesize(hp, filesizestr, filename);
  651.             }
  652.             if (eval_result)
  653.             {
  654.                 set_vartext(dest, eval_result);
  655.                 eval_result = get_vartext(dest);
  656.             }
  657.             del_hscattr(filedestattr);
  658.             del_estr(filesizestr);
  659.         }
  660.         else if (!upstrcmp(nw, "GETTIME"))
  661.         {
  662.             /* get local time */
  663.             EXPSTR *timestr = gettimestr(hp, localtime(&(hp->start_time)));
  664.  
  665.             D(fprintf(stderr, DHL "  GETTIME\n"));
  666.             if (timestr)
  667.             {
  668.                 set_vartext(dest, estr2str(timestr));
  669.                 del_estr(timestr);
  670.                 eval_result = get_vartext(dest);
  671.             }
  672.             check_brakets(hp);
  673.         }
  674.         else if (!upstrcmp(nw, "GETGMTIME"))
  675.         {
  676.             /* get greenwich mean time */
  677.             EXPSTR *timestr = gettimestr(hp, gmtime(&(hp->start_time)));
  678.  
  679.             D(fprintf(stderr, DHL "  GETGMTIME\n"));
  680.             if (timestr)
  681.             {
  682.                 set_vartext(dest, estr2str(timestr));
  683.                 del_estr(timestr);
  684.                 eval_result = get_vartext(dest);
  685.             }
  686.             check_brakets(hp);
  687.         }
  688.         else if (!upstrcmp(nw, "SET"))
  689.         {
  690.  
  691.             nw = eval_attrname(hp);
  692.             if (nw)
  693.             {
  694.                 HSCATTR *attr = find_varname(hp->defattr, nw);
  695.  
  696.                 if (attr)
  697.                 {
  698.                     if (attr->vartype == VT_BOOL)
  699.                     {
  700.                         set_varbool(dest, get_varbool(attr));
  701.                     }
  702.                     else if (get_vartext(attr))
  703.                         set_varbool(dest, TRUE);
  704.                     else
  705.                         set_varbool(dest, FALSE);
  706.                     eval_result = get_vartext(dest);
  707.                 }
  708.                 else
  709.                 {
  710.                     hsc_msg_unkn_attr(hp, nw);
  711.                     *err = TRUE;
  712.                 }
  713.             }
  714.         }
  715.         else
  716.             inungetcw(inpf);
  717.     }
  718.  
  719.     del_hscattr(tmpdest);
  720.  
  721.     if (!nw)
  722.         *err = TRUE;
  723.  
  724.     return (eval_result);
  725. }
  726.  
  727. /*
  728.  * eval_op
  729.  *
  730.  * evaluate binary operator string
  731.  */
  732. static BYTE eval_op(HSCPRC * hp)
  733. {
  734.     BYTE op = OP_NONE;
  735.     BOOL op_eof = FALSE;        /* flag: end of file reached */
  736.     INFILE *inpf = hp->inpf;
  737.     STRPTR nw = infgetw(inpf);
  738.  
  739.     D(fprintf(stderr, DHL "  operator \"%s", nw));
  740.  
  741.     if (nw)
  742.     {
  743.         /* boolean operators */
  744.         if (!upstrcmp(nw, OP_AND_STR))
  745.             op = OP_AND;
  746.         else if (!upstrcmp(nw, OP_OR_STR))
  747.             op = OP_OR;
  748.         else if (!upstrcmp(nw, OP_XOR_STR))
  749.             op = OP_XOR;
  750.  
  751.         /* concatenation operator */
  752.         else if (!strcmp(nw, OP_CAT_STR))
  753.             op = OP_CAT;
  754.  
  755.         /* closing braket */
  756.         else if (!strcmp(nw, OP_CL_BRAKET_STR))
  757.             op = OP_CL_BRAKET;
  758.  
  759.         /* comparison operators */
  760.         else if (strenum(nw, "<|=|>", '|', STEN_CASE))
  761.         {
  762.             STRARR opstr[3];
  763.             int ch;
  764.  
  765.             /* determine whole comparison operator:
  766.              * take first word, and check for next
  767.              * single character, if it is one of
  768.              * "<", "=" or ">", too. if so, append
  769.              * it to the string that tells the
  770.              * operator.
  771.              */
  772.             strcpy(opstr, nw);
  773.             ch = infgetc(inpf);
  774.             if (ch != EOF)
  775.             {
  776.                 D(fprintf(stderr, "%c", (char) ch));
  777.  
  778.                 if (strchr("<=>", ch))
  779.                 {
  780.                     opstr[1] = ch;
  781.                     opstr[2] = 0;
  782.                 }
  783.                 else
  784.                     inungetc(ch, inpf);
  785.             }
  786.             else
  787.                 op_eof = TRUE;
  788.  
  789.             /* find out comparison operator */
  790.             if (!strcmp(nw, OP_EQ_STR))
  791.                 op = OP_EQ;
  792.             else if (!strcmp(nw, OP_NEQ_STR))
  793.                 op = OP_EQ;
  794.             else if (!strcmp(nw, OP_GT_STR))
  795.                 op = OP_GT;
  796.             else if (!strcmp(nw, OP_LT_STR))
  797.                 op = OP_LT;
  798.             else if (!strcmp(nw, OP_LTE_STR))
  799.                 op = OP_LTE;
  800.             else if (!strcmp(nw, OP_GTE_STR))
  801.                 op = OP_GTE;
  802.             else if (!strcmp(nw, OP_CEQ_STR))
  803.                 op = OP_CEQ;
  804.             else
  805.                 err_op(hp, opstr);
  806.         }
  807.         else
  808.             err_op(hp, nw);
  809.  
  810.     }
  811.     else
  812.         op_eof = TRUE;
  813.  
  814.     D(fprintf(stderr, "\"\n"));
  815.  
  816.     if (op_eof)
  817.         hsc_msg_eof(hp, "operator expected");
  818.  
  819.     return (op);
  820. }
  821.  
  822. /*
  823.  * process_op
  824.  */
  825. static VOID process_op(HSCPRC * hp, HSCATTR * dest, BYTE op, STRPTR str1, STRPTR str2)
  826. {
  827.     EXPSTR *result = init_estr(40);
  828.     BOOL result_set = FALSE;
  829.  
  830.     D(fprintf(stderr, DHL "  \"%s\", \"%s\"\n", str1, str2));
  831.     if (str2 && (op != OP_NONE))
  832.     {
  833.         BOOL bool_val1 = eval_boolstr(str1);
  834.         BOOL bool_val2 = eval_boolstr(str2);
  835.  
  836.         switch (op)
  837.         {
  838.         case OP_AND:
  839.             if (bool_val1 && bool_val2)
  840.                 set_varbool(dest, TRUE);
  841.             else
  842.                 set_varbool(dest, FALSE);
  843.             break;
  844.  
  845.         case OP_OR:
  846.             if (bool_val1 || bool_val2)
  847.                 set_varbool(dest, TRUE);
  848.             else
  849.                 set_varbool(dest, FALSE);
  850.             break;
  851.  
  852.         case OP_XOR:
  853.             if ((bool_val1 || bool_val2)
  854.                 && !(bool_val1 && bool_val2)
  855.                 )
  856.                 set_varbool(dest, TRUE);
  857.             else
  858.                 set_varbool(dest, FALSE);
  859.             break;
  860.  
  861.         case OP_EQ:
  862.  
  863.             /* string comparison, ignore case */
  864.             if (!upstrcmp(str1, str2))
  865.                 set_varbool(dest, TRUE);
  866.             else
  867.                 set_varbool(dest, FALSE);
  868.             break;
  869.  
  870.         case OP_NEQ:
  871.  
  872.             /* string comparison "<>" */
  873.             if (upstrcmp(str1, str2))
  874.                 set_varbool(dest, TRUE);
  875.             else
  876.                 set_varbool(dest, FALSE);
  877.             break;
  878.  
  879.         case OP_GT:
  880.  
  881.             /* string comparison ">" */
  882.             if (upstrcmp(str1, str2) > 0)
  883.                 set_varbool(dest, TRUE);
  884.             else
  885.                 set_varbool(dest, FALSE);
  886.             break;
  887.  
  888.         case OP_LT:
  889.  
  890.             /* string comparison "<" */
  891.             if (upstrcmp(str1, str2) < 0)
  892.                 set_varbool(dest, TRUE);
  893.             else
  894.                 set_varbool(dest, FALSE);
  895.             break;
  896.  
  897.         case OP_GTE:
  898.  
  899.             /* string comparison ">=" */
  900.             if (upstrcmp(str1, str2) >= 0)
  901.                 set_varbool(dest, TRUE);
  902.             else
  903.                 set_varbool(dest, FALSE);
  904.             break;
  905.  
  906.         case OP_LTE:
  907.  
  908.             /* string comparison "<=" */
  909.             if (upstrcmp(str1, str2) <= 0)
  910.                 set_varbool(dest, TRUE);
  911.             else
  912.                 set_varbool(dest, FALSE);
  913.             break;
  914.  
  915.         case OP_CEQ:
  916.  
  917.             /* string comparison, case sensitive */
  918.             if (!strcmp(str1, str2))
  919.                 set_varbool(dest, TRUE);
  920.             else
  921.                 set_varbool(dest, FALSE);
  922.             break;
  923.  
  924.         case OP_CAT:
  925.  
  926.             /* concat two expressions */
  927.             set_estr(result, str1);
  928.             app_estr(result, str2);
  929.             result_set = TRUE;
  930.  
  931.             break;
  932.  
  933.         default:
  934.             panic("empty operator");
  935.             break;
  936.         }
  937.     }
  938.     /* store result in destination attribute,
  939.      * if this has not happened yet
  940.      */
  941.     if (result_set)
  942.         set_vartext(dest, estr2str(result));
  943.  
  944.     /* remove temp. string for result */
  945.     del_estr(result);
  946. }
  947.  
  948. /*
  949.  *-------------------------------------
  950.  * eval_expression: evaluate expression
  951.  *-------------------------------------
  952.  */
  953.  
  954. /*
  955.  * eval_string_expr
  956.  *
  957.  * evaluate string expression WITH enclosing quotes
  958.  */
  959. static STRPTR eval_string_expr(HSCPRC * hp, HSCATTR * dest)
  960. {
  961.     INFILE *inpf = hp->inpf;
  962.     STRPTR eval_result = NULL;
  963.     EXPSTR *tmpstr = init_estr(TMP_STEPSIZE);
  964.     int quote;
  965.  
  966.     /* get quote char */
  967.     quote = infgetc(inpf);
  968.     if (quote != EOF)
  969.     {
  970.         BOOL end = FALSE;
  971.  
  972.         while (!end)
  973.         {
  974.             int ch = infgetc(inpf);
  975.             if (ch == EOF)
  976.             {
  977.                 hsc_msg_eof(hp, "reading string constant");
  978.                 eval_result = NULL;
  979.                 end = TRUE;
  980.             }
  981.             else if (ch != quote)
  982.             {
  983.                 /* check for LF inside string */
  984.                 if (ch == '\n')
  985.                     hsc_message(hp, MSG_STR_LF,
  986.                                 "linefeed found inside string");
  987.  
  988.                 /* append next char to string */
  989.                 app_estrch(tmpstr, ch);
  990.             }
  991.             else
  992.             {
  993.                 /* closing quote reached */
  994.                 eval_result = estr2str(tmpstr);
  995.                 end = TRUE;
  996.             }
  997.         }
  998.     }
  999.     else
  1000.         hsc_msg_eof(hp, "reading string constant");
  1001.  
  1002.     /* set new attribute value */
  1003.     if (eval_result)
  1004.     {
  1005.         /* set new quotes */
  1006.         dest->quote = quote;
  1007.         /* set new value */
  1008.         set_vartext(dest, eval_result);
  1009.         eval_result = get_vartext(dest);
  1010.     }
  1011.     /* remove temp. string */
  1012.     del_estr(tmpstr);
  1013.  
  1014.     return (eval_result);
  1015. }
  1016.  
  1017. /*
  1018.  * eval_string_expr_noquote
  1019.  *
  1020.  * evaluate string expression WITHOUT enclosing quotes
  1021.  */
  1022. STRPTR eval_string_expr_noquote(HSCPRC * hp, HSCATTR * dest)
  1023. {
  1024.     /* TODO: check for ch==">": attrval missing */
  1025.     INFILE *inpf = hp->inpf;
  1026.     STRPTR eval_result = NULL;
  1027.     EXPSTR *tmpstr = init_estr(TMP_STEPSIZE);
  1028.     BOOL end = FALSE;
  1029.  
  1030.     /* TODO: check for empty expression */
  1031.  
  1032.     /*
  1033.      * read next char from input file until a
  1034.      * closing quote if found.
  1035.      * if the arg had no quote, a white space
  1036.      * or a '>' is used to detect end of arg.
  1037.      * if a LF is found, view error message
  1038.      */
  1039.     while (!end)
  1040.     {
  1041.  
  1042.         int ch = infgetc(inpf);
  1043.         if (ch == EOF)
  1044.         {
  1045.             hsc_msg_eof(hp, "reading attribute");
  1046.  
  1047.             end = TRUE;
  1048.         }
  1049.         else if ((ch == '\n')
  1050.                  || (inf_isws(ch, inpf) || (ch == '>')))
  1051.         {
  1052.             /* end of arg reached */
  1053.             inungetc(ch, inpf);
  1054.             eval_result = estr2str(tmpstr);
  1055.             end = TRUE;
  1056.         }
  1057.         else
  1058.         {
  1059.             /* append next char to tmpstr */
  1060.             app_estrch(tmpstr, ch);
  1061.         }
  1062.     }
  1063.  
  1064.     /* set new attribute value */
  1065.     if (eval_result)
  1066.     {
  1067.         set_vartext(dest, eval_result);
  1068.         eval_result = get_vartext(dest);
  1069.     }
  1070.     /* remove temp. string */
  1071.     del_estr(tmpstr);
  1072.  
  1073.     return (eval_result);
  1074. }
  1075.  
  1076. /*
  1077.  * eval_attrref
  1078.  *
  1079.  * evaluate reference to attribute
  1080.  *
  1081.  */
  1082. static STRPTR eval_attrref(HSCPRC * hp, HSCATTR * destattr)
  1083. {
  1084.     STRPTR eval_result = NULL;
  1085.     STRPTR nw = eval_attrname(hp);
  1086.  
  1087.     if (nw)
  1088.     {
  1089.         HSCATTR *refvar = find_varname(hp->defattr, nw);
  1090.  
  1091.         if (refvar)
  1092.         {
  1093.             /* TODO: type checking */
  1094.             destattr->quote = refvar->quote;
  1095.             eval_result = refvar->text;
  1096.  
  1097.             /* check empty/circular reference */
  1098.             if (!eval_result)
  1099.                 hsc_message(hp, MSG_EMPTY_SYMB_REF,
  1100.                             "empty reference to %A", destattr);
  1101.  
  1102.             /* debugging message */
  1103.             DDA(fprintf(stderr, DHL "   %s refers to (%s)\n",
  1104.                         destattr->name, refvar->name));
  1105.         }
  1106.         else
  1107.         {
  1108.             /* reference to unknown destattr */
  1109.             hsc_msg_unkn_attr(hp, nw);
  1110.         }
  1111.  
  1112.         /* set empty value for reference to NULL */
  1113.         if ((!refvar) || (!eval_result))
  1114.         {
  1115.             /* return empty destattr */
  1116.             destattr->quote = '"';
  1117.             eval_result = "";
  1118.         }
  1119.     }
  1120.  
  1121.     /* set value of destination attribute */
  1122.     if (eval_result)
  1123.         set_vartext(destattr, eval_result);
  1124.  
  1125.     return (eval_result);
  1126. }
  1127.  
  1128. /*
  1129.  * eval_expression
  1130.  *
  1131.  * params: dest....attribute where to store result in
  1132.  *         inpf....input file
  1133.  *         err.....flag that is set to TRUE if an error occured
  1134.  *         endstr..word that is expected at end of expession;
  1135.  *                 NULL for no special ending word
  1136.  * result: result of evaluation (IF_TRUE or FALSE)
  1137.  *
  1138.  * NOTE: if endstr==NULL, that means that eval_expression() is called
  1139.  *   immediatly after the "=" of an attribute. In this case, if no
  1140.  *   quotes are found as next char, all chars are read until the next
  1141.  *   white-space or LF occures.
  1142.  *   If no special char was found until now (only "A".."Z", "_", "-" and
  1143.  *   digits occured), we first interpret the string as name for an
  1144.  *   attribute reference; if such an attribute does not exist, it is
  1145.  *   asumed that the value passed is a string constant (same as it would
  1146.  *   have been enclosed in quotes).
  1147.  *
  1148.  */
  1149. STRPTR eval_expression(HSCPRC * hp, HSCATTR * dest, STRPTR endstr)
  1150. {
  1151.     /* TODO: endstr needs to be boolean flag only */
  1152.     INFILE *inpf = hp->inpf;
  1153.     EXPSTR *vararg = init_estr(TMP_STEPSIZE);
  1154.     /* used as destination by eval_string_exprXX() */
  1155.  
  1156.     STRPTR exprstr = NULL;      /* return value */
  1157.     int ch;                     /* char read from input */
  1158.  
  1159.     /* skip white spaces */
  1160.     infskip_ws(inpf);
  1161.  
  1162.     /* read dest->quote char */
  1163.     ch = infgetc(inpf);
  1164.     if (!strchr(VQ_STR_QUOTE, ch))
  1165.         if (ch != EOF)
  1166.             dest->quote = VQ_NO_QUOTE;
  1167.         else
  1168.             hsc_msg_eof(hp, "reading attribute");
  1169.     else
  1170.         dest->quote = ch;
  1171.  
  1172.     if (ch == '(')
  1173.     {
  1174.         /* process braket */
  1175.         exprstr = eval_expression(hp, dest, ")");
  1176.  
  1177.         /* set generic double quote */
  1178.         if (!endstr)
  1179.             dest->quote = '\"';
  1180.     }
  1181.     else if (ch != EOF)
  1182.     {
  1183.         /* write current char read back to input buffer */
  1184.         inungetc(ch, inpf);
  1185.  
  1186.         if (dest->quote != VQ_NO_QUOTE)
  1187.         {
  1188.             /* process string expression with quotes */
  1189.             exprstr = eval_string_expr(hp, dest);
  1190.         }
  1191.         else if (endstr)
  1192.         {
  1193.             BOOL err = FALSE;
  1194.  
  1195.             /* try to process unary operator */
  1196.             exprstr = try_eval_unary_op(hp, dest, &err);
  1197.  
  1198.             /* process attribute reference */
  1199.             if (!exprstr && !err)
  1200.                 exprstr = eval_attrref(hp, dest);
  1201.         }
  1202.         else
  1203.         {
  1204.             /* process string expression without quotes */
  1205.             exprstr = eval_string_expr_noquote(hp, dest);
  1206.         }
  1207.     }
  1208.  
  1209.     if (exprstr && endstr)
  1210.     {
  1211.         BYTE op;
  1212.  
  1213.         /* evaluate operator */
  1214.         op = eval_op(hp);
  1215.  
  1216.         if (op == OP_CL_BRAKET)
  1217.             DMSG("  END mark operator reached");
  1218.         else if (op != OP_NONE)
  1219.         {
  1220.             /* no endmark reached */
  1221.             STRPTR str1 = exprstr;
  1222.  
  1223.             /* read second operator */
  1224.             if (op != OP_NONE)
  1225.             {
  1226.                 STRPTR str2 = NULL;
  1227.                 HSCATTR *dest1 = new_hscattr(PREFIX_TMPATTR "2nd.operand");
  1228.  
  1229.                 /* init dummy attribute */
  1230.                 dest1->vartype = dest->vartype;
  1231.                 dest1->quote = dest->quote;
  1232.  
  1233.                 /* compute second value */
  1234.                 str2 = eval_expression(hp, dest1, endstr);
  1235.  
  1236.                 if (str2)
  1237.                     process_op(hp, dest, op, str1, str2);
  1238.                 else
  1239.                     exprstr = NULL;
  1240.  
  1241.                 /* remove result of second value */
  1242.                 del_hscattr((APTR) dest1);
  1243.             }
  1244.             else
  1245.             {
  1246.                 /* TODO: skip expression until ">" */
  1247.                 exprstr = NULL;
  1248.             }
  1249.  
  1250.             if (exprstr)
  1251.             {
  1252.                 /* store result */
  1253.                 exprstr = get_vartext(dest);
  1254.             }
  1255.         }
  1256.         else
  1257.         {
  1258.             DMSG("  NO operator");
  1259.         }
  1260.     }
  1261.  
  1262.     if (!endstr)
  1263.     {
  1264.         if (exprstr && !endstr)
  1265.         {
  1266.             if ((dest->vartype != VT_BOOL)
  1267.                 && !(dest->varflag & (VF_MACRO | VF_KEEP_QUOTES)))
  1268.             {
  1269.                 choose_quote(hp, dest);
  1270.             }
  1271.  
  1272.             /*
  1273.              * check enum type
  1274.              */
  1275.             if (dest->vartype == VT_ENUM)
  1276.             {
  1277.                 if (!strenum(exprstr, dest->enumstr, '|', STEN_NOCASE))
  1278.                 {
  1279.                     /* unknown enum value */
  1280.                     hsc_message(hp, MSG_ENUM_UNKN,
  1281.                                 "unknown value %q for enumerator %A",
  1282.                                 exprstr, dest);
  1283.                 }
  1284.             }
  1285.             /*
  1286.              * check color value
  1287.              */
  1288.             else if (dest->vartype == VT_COLOR)
  1289.             {
  1290.                 BOOL ok = FALSE;
  1291.                 size_t color_len = strlen("#rrggbb");
  1292.  
  1293.                 if (exprstr[0] == '#')
  1294.                 {
  1295.                     /* check RGB-value */
  1296.                     if (strlen(exprstr) == color_len)
  1297.                     {
  1298.                         size_t i = 1;
  1299.  
  1300.                         ok = TRUE;
  1301.                         for (; i < color_len; i++)
  1302.                             if (!isxdigit(exprstr[i]))
  1303.                                 ok = FALSE;
  1304.                     }
  1305.                 }
  1306.                 else
  1307.                 {
  1308.                     /* check color name */
  1309.                     if (hp->color_names)
  1310.                     {
  1311.                         if (strenum(exprstr, hp->color_names, '|', STEN_NOCASE))
  1312.                             ok = TRUE;
  1313.                     }
  1314.                     else
  1315.                         ok = TRUE;
  1316.                 }
  1317.  
  1318.                 if (!ok)
  1319.                     /* illegal color value */
  1320.                     hsc_message(hp, MSG_ILLG_COLOR,
  1321.                                 "illegal color value %q for %A",
  1322.                                 exprstr, dest);
  1323.             }
  1324.             /*
  1325.              * check numeric value
  1326.              */
  1327.             else if (dest->vartype == VT_NUM)
  1328.             {
  1329.                 BOOL ok = FALSE;
  1330.                 int i = 0;
  1331.  
  1332.                 if ((exprstr[0] == '+')
  1333.                     || (exprstr[0] == '-'))
  1334.                 {
  1335.                     i = 1;
  1336.                 }
  1337.                 if (strlen(exprstr) - i)
  1338.                 {
  1339.                     ok = TRUE;
  1340.                     while (exprstr[i] && ok)
  1341.                     {
  1342.                         if (!isdigit(exprstr[i]))
  1343.                             ok = FALSE;
  1344.                         else
  1345.                             i++;
  1346.                     }
  1347.                 }
  1348.                 if (!ok)
  1349.                     /* unknown enum value */
  1350.                     hsc_message(hp, MSG_ILLG_NUM,
  1351.                                 "illegal numeric value %q for %A",
  1352.                                 exprstr, dest);
  1353.             }
  1354.             /*
  1355.              * for boolean attributes, set the name
  1356.              * of the attribute if TRUE, or set an
  1357.              * empty string, if FALSE
  1358.              */
  1359.             else if (dest->vartype == VT_BOOL)
  1360.                 if (eval_boolstr(exprstr))
  1361.                     set_vartext(dest, dest->name);
  1362.                 else
  1363.                     set_vartext(dest, "");
  1364.  
  1365.             /*
  1366.              * checks performed only for tags,
  1367.              * but are skipped for macros
  1368.              */
  1369.             if (!(dest->varflag & VF_MACRO))
  1370.             {
  1371.                 /*
  1372.                  * parse uri (convert abs.uris, check existence)
  1373.                  */
  1374.                 if (dest->vartype == VT_URI)
  1375.                 {
  1376.                     EXPSTR *dest_uri = init_estr(32);
  1377.  
  1378.                     parse_uri(hp, dest_uri, exprstr);
  1379.                     set_vartext(dest, estr2str(dest_uri));
  1380.  
  1381.                     del_estr(dest_uri);
  1382.                 }
  1383.             }
  1384.             exprstr = get_vartext(dest);
  1385.         }
  1386.         else
  1387.         {
  1388.             /* if error occured,
  1389.              * skip until ">", unread ">"
  1390.              */
  1391.             skip_until_eot(hp, NULL);
  1392.             if (!hp->fatal)
  1393.                 inungetcw(inpf);
  1394.         }
  1395.     }
  1396.  
  1397.     del_estr(vararg);
  1398.  
  1399.     return (exprstr);
  1400. }
  1401.  
  1402. /*
  1403.  * eval_cloneattr
  1404.  *
  1405.  * read name of attribute, check if it has been set;
  1406.  * if so, return value of attribute.
  1407.  * all possible errors are handled by this function.
  1408.  *
  1409.  * params: hp.....hsc-process
  1410.  *         dest...detination attribute where to store value
  1411.  * result: value of attribute, if it has been set, or NULL
  1412.  *         if attribute is empty or unknown or other error
  1413.  *         has occured.
  1414.  */
  1415. STRPTR eval_cloneattr(HSCPRC * hp, HSCATTR * dest)
  1416. {
  1417.     STRPTR nw = eval_attrname(hp);
  1418.     STRPTR attrval = NULL;
  1419.  
  1420.     if (nw)
  1421.     {
  1422.         HSCATTR *attr = find_varname(hp->defattr, nw);
  1423.  
  1424.         if (attr)
  1425.         {
  1426.             attrval = get_vartext(attr);
  1427.             dest->quote = attr->quote;
  1428.         }
  1429.         else
  1430.             hsc_msg_unkn_attr(hp, nw);
  1431.     }
  1432.  
  1433.     /* update attribute value and quotes */
  1434.     if (attrval)
  1435.     {
  1436.         set_vartext(dest, attrval);
  1437.         attrval = get_vartext(dest);
  1438.         choose_quote(hp, dest);
  1439.     }
  1440.  
  1441.     return (attrval);
  1442. }
  1443.  
  1444.